/*
Punchit -- A simple timer of accumulated time (survives restarts).
Copyright (c) 2006 D. Robert Adams

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

var totalTime = 0;   // total amount of accumulated time so far
var startTime = 0;   // when the timer was start
var elapsedTime = 0; // elapsed time since startTime
var running = false; // is the timer running?

/****************************************************************************
 * Called when the widget is launched.  Reads preferences.
 */
function setup()
{
  // The preferences are retrieved:
  totalTime = parseInt( getPref('totalTime', '0') );
  startTime = parseInt( getPref("startTime", '0' ));
  elapsedTime = parseInt( getPref("elapsedTime", 0));
  running = getPref("running", false);
    
  // Disable a button when we begin.
  if ( running ) {
    startButton.onclick = false;
    startButton.src="b_button_play.png";
  }
  else {
    stopButton.onclick = false;
    stopButton.src="b_button_pause.png";
  }
  
  // Set up some handlers for when the widget is shown and hidden.
  widget.onshow = handleWidgetShown
	widget.onhide = handleWidgetHidden
}

/****************************************************************************
 * Returns the preference string or the defaultVal if the preference does
 * not exit.
 */
function getPref(keyStr, defaultVal)
{
  var strVal = widget.preferenceForKey(keyStr);
  if (typeof strVal == "undefined")
    return defaultVal;
  else
    return strVal;
}

/****************************************************************************
 * Called whenever the widget is displayed.  Update the elapsed time.
 */
function handleWidgetShown()
{
  updateTime();
  if ( running )
    timerInterval = setInterval("updateTime();", 1000);
}

/****************************************************************************
 * Updates the displayed time.
 */
function updateTime()
{
    // Update the elapsed time so far if the timer is running.
  if ( running ) {
    var date = new Date();
    var time = Math.floor(date.getTime() / 1000);
    elapsedTime = time - startTime;
  }
  
  // Display the elapsed time so far.
  var SEC_PER_HOUR = 60*60;
  var SEC_PER_MIN  = 60;

  var iElapsedTime = totalTime + elapsedTime;
  
  var hours = Math.floor(iElapsedTime / SEC_PER_HOUR);
  iElapsedTime = iElapsedTime - hours*SEC_PER_HOUR;
  
  var minutes = Math.floor(iElapsedTime  / SEC_PER_MIN);
  iElapsedTime = iElapsedTime - minutes*SEC_PER_MIN;
  
  var seconds = iElapsedTime;
  
  var sElapsed = twoDigits(hours) + ":" + twoDigits(minutes) + ":" + twoDigits(seconds);
  elapsedTimeLabel.innerHTML = sElapsed;
}

/****************************************************************************
 * Returns a string version of num padded to at least two digits.
 */
function twoDigits(num)
{
  if (num >= 10)
    return "" + num;
  else
    return "0" + num;
}

/****************************************************************************
 * Called whenever the widget is hidden.  Store the current values.
 */
function handleWidgetHidden()
{
  clearInterval(timerInterval);
  widget.setPreferenceForKey(totalTime, "totalTime");
  widget.setPreferenceForKey(elapsedTime, "elapsedTime");
  widget.setPreferenceForKey(startTime, "startTime");
  widget.setPreferenceForKey(running, "running");
}
 
/****************************************************************************
 * BUTTON FUNCTIONS
 ****************************************************************************/

/****************************************************************************/
function start()
{
  // Disable the other button.
  startButton.onclick = false;
  startButton.src="b_button_play.png";

  stopButton.onclick = stop;
  stopButton.src="button_pause.png";
 
  // Get the new startTime.
  running = true;
  var date = new Date();
  var time = Math.floor(date.getTime() / 1000);
  startTime = time;
  
  handleWidgetShown();
}
/***************************************************************************/
function stop()
{
  // Update the displayed time.
  updateTime();
  
  // Disable the start button.
  startButton.onclick = start;
  startButton.src="button_play.png";

  stopButton.onclick = false;
  stopButton.src="b_button_pause.png";
  
  // Update the total time so far and stop the clock.
  totalTime = totalTime + elapsedTime;
  running = false;
  elapsedTime = 0;
}
/***************************************************************************/
function reset()
{
  // Reset the system.
  startButton.onclick = start;
  startButton.src="button_play.png";
  stopButton.onclick = false;
  stopButton.src="b_button_pause.png";

  totalTime = 0;
  elapsedTime = 0;
  startTime = 0;
  running = false;
  
  // Update the display.
  updateTime();
}

/****************************************************************************
 * BACK FUNCTIONS
 ****************************************************************************/
function addTime()
{
  var minutes = parseInt(addBox.value);
  if ( ! isNaN(minutes) ) {
    totalTime = totalTime + (minutes * 60);
  }
}

/***************************************************************************
 * FLIPPING FUNCTIONS
 * Standard stuff to flip the widget over.  Copied directly from Apple's
 * Goodbye World example, and slightly modified by me!
 ***************************************************************************/

// these functions are called when the info button itself receives 
// onmouseover and onmouseout events
function enterflip(event)
{
	document.getElementById('fliprollie').style.display = 'block';
}

function exitflip(event)
{
	document.getElementById('fliprollie').style.display = 'none';
}

// showBack() is called when the preferences flipper is clicked upon.  
// It freezes the front of the widget, hides the front div, unhides the back 
// div, and then flips the widget over.
function showBack()
{
	var front = document.getElementById("front");
	var back = document.getElementById("back");
	
	if (window.widget)
		widget.prepareForTransition("ToBack");		// freezes the widget so that you can change it without the user noticing
	
	front.style.display="none";		// hide the front
	back.style.display="block";		// show the back
	
	if (window.widget)
		setTimeout ('widget.performTransition();', 0);		// and flip the widget over	

	document.getElementById('fliprollie').style.display = 'none';  // clean up the front side - hide the circle behind the info button
}

// showFront() is called by the done button on the back side of the widget.
// It performs the opposite transition as showBack() does.
function showFront()
{ 
	var front = document.getElementById("front");
	var back = document.getElementById("back");
	
	if (window.widget)
		widget.prepareForTransition("ToFront");		// freezes the widget and prepares it for the flip back to the front
	
	back.style.display="none";			// hide the back
	front.style.display="block";		// show the front
	
	if (window.widget)
		setTimeout ('widget.performTransition();', 0);		// and flip the widget back to the front
  updateTime();
}

/****************************************************************************
 * i BUTTON FUNCTIONS
 * Standard stuff to make the i button appear when the mouse moves into
 * the widget area.  Copied directly from Goodbye World example.
 ****************************************************************************/

// PREFERENCE BUTTON ANIMATION (- the pref flipper fade in/out)
var flipShown = false;		// a flag used to signify if the flipper is currently shown or not.

// A structure that holds information that is needed for the animation to run.
var animation = {duration:0, starttime:0, to:1.0, now:0.0, from:0.0, firstElement:null, timer:null};

// mousemove() is the event handle assigned to the onmousemove property on the front div of the widget. 
// It is triggered whenever a mouse is moved within the bounds of your widget.  It prepares the
// preference flipper fade and then calls animate() to performs the animation.
function mousemove (event)
{
	if (!flipShown)			// if the preferences flipper is not already showing...
	{
		if (animation.timer != null)			// reset the animation timer value, in case a value was left behind
		{
			clearInterval (animation.timer);
			animation.timer  = null;
		}
		
		var starttime = (new Date).getTime() - 13; 		// set it back one frame
		
		animation.duration = 500;												// animation time, in ms
		animation.starttime = starttime;										// specify the start time
		animation.firstElement = document.getElementById ('flip');		// specify the element to fade
		animation.timer = setInterval ("animate();", 13);						// set the animation function
		animation.from = animation.now;											// beginning opacity (not ness. 0)
		animation.to = 1.0;														// final opacity
		animate();																// begin animation
		flipShown = true;														// mark the flipper as animated
	}
}

// mouseexit() is the opposite of mousemove() in that it preps the preferences flipper
// to disappear.  It adds the appropriate values to the animation data structure and sets the animation in motion.
function mouseexit (event)
{
	if (flipShown)
	{
		// fade in the flip widget
		if (animation.timer != null)
		{
			clearInterval (animation.timer);
			animation.timer  = null;
		}
		
		var starttime = (new Date).getTime() - 13;
		
		animation.duration = 500;
		animation.starttime = starttime;
		animation.firstElement = document.getElementById ('flip');
		animation.timer = setInterval ("animate();", 13);
		animation.from = animation.now;
		animation.to = 0.0;
		animate();
		flipShown = false;
	}
}

// animate() performs the fade animation for the preferences flipper. It uses the opacity CSS property to simulate a fade.
function animate()
{
	var T;
	var ease;
	var time = (new Date).getTime();
		
	
	T = limit_3(time-animation.starttime, 0, animation.duration);
	
	if (T >= animation.duration)
	{
		clearInterval (animation.timer);
		animation.timer = null;
		animation.now = animation.to;
	}
	else
	{
		ease = 0.5 - (0.5 * Math.cos(Math.PI * T / animation.duration));
		animation.now = computeNextFloat (animation.from, animation.to, ease);
	}
	
	animation.firstElement.style.opacity = animation.now;
}


// these functions are utilities used by animate()
function limit_3 (a, b, c)
{
    return a < b ? b : (a > c ? c : a);
}

function computeNextFloat (from, to, ease)
{
    return from + (to - from) * ease;
}


